<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>WebGL-10.使用三角扇的方式绘制矩形</title>
</head>
<body>
  <canvas id="glcanvas" width="640" height="480"></canvas>
  <div>
    <label>使用四个三角形拼接<input type="radio" name="count" value="four" /></label>
    <label>使用两个三角形拼接<input type="radio" name="count" value="two" /></label>
  </div>
  <script type="shader-source" id="vertexShader">
    // 设置浮点精度为中等精度
    precision mediump float;
    // 接收点在canvas坐标系的坐标
    attribute vec2 a_Position;
    // 接收canvas的宽高
    attribute vec2 a_Screen_Size;
    // 接收颜色
    attribute vec4 a_Color;
    // 透传颜色
    varying vec4 v_Color;
    void main() {
      // 将屏幕坐标系转成裁剪坐标系
      vec2 position = (a_Position / a_Screen_Size) * 2.0 - 1.0;
      // canvas的 Y 轴坐标方向和 设备坐标系的相反。
      position = position * vec2(1.0, -1.0);
      gl_Position = vec4(position, 0.0, 1.0);

      // 声明要绘制的点的大小
      gl_PointSize = 5.0;
      // 透传颜色
      v_Color = a_Color;
    }
  </script>
  <script type="shader-source" id="fragmentShader">
    // 设置浮点精度为中等精度
    precision mediump float;
    // 接收从顶点着色器透传过来的颜色
    varying vec4 v_Color;
    void main() {
      // 将不同的颜色表示转换成webgl的颜色表示【0，1】
      vec4 color = v_Color / vec4(255, 255, 255, 1);
      // 设置像素颜色为红色
      gl_FragColor = color;
    }
  </script>
  <script id="webgl-helper">
    /**
     * 创建着色器
     * @this gl
     * @param shaderType 着色器类型
     * @param sourceId 着色器源码id
     * @return shader 着色器
    */
    function createShader(shaderType, sourceId) {
      // 获取着色器源码
      var shaderSource = document.querySelector(sourceId).innerHTML;
      // 创建着色器
      var shader = this.createShader(shaderType);
      // 将源码与着色器绑定
      this.shaderSource(shader, shaderSource);
      // 编译着色器
      this.compileShader(shader);
      return shader;
    }

    /**
     * 创建着色器程序&绑定着色器
     * @this gl
     * @param arguments 着色器数组
     * @return program 着色器程序
    */
    function createProgram() {
      // 创建周色器程序
      var program = this.createProgram();
      for (var i = 0; i < arguments.length; i++) {
        // 将着色器挂在着色器程序上
        this.attachShader(program, arguments[i]);
      }
      // 连接着色器程序
      this.linkProgram(program);
      return program;
    }
  </script>
  <script>
    (function() {
      var canvas = document.getElementById('glcanvas');
      var gl = canvas.getContext('webgl');

      // 创建顶点着色器对象
      var vertexShader = createShader.call(gl, gl.VERTEX_SHADER, '#vertexShader');
      // 创建片元着色器对象
      var fragmentShader = createShader.call(gl, gl.FRAGMENT_SHADER, '#fragmentShader');
      // 创建着色器程序
      var program = createProgram.apply(gl, [vertexShader, fragmentShader]);

      // 启用着色器程序（通常有多个程序) 使用前先启动
      gl.useProgram(program);

      // 获取顶点着色器的变量
      var aPosition = gl.getAttribLocation(program, 'a_Position');
      var aScreenSize = gl.getAttribLocation(program, 'a_Screen_Size');
      var aColor = gl.getAttribLocation(program, 'a_Color');
      // 启用属性
      gl.enableVertexAttribArray(aPosition);
      gl.enableVertexAttribArray(aColor);
      // 为顶点着色器传递canvas宽高
      gl.vertexAttrib2f(aScreenSize, canvas.width, canvas.height);

      //存储顶点信息的数组
      /**
      * 注意三角扇的顶点顺序很重要
      * 使用三角扇绘制矩形，选中中间点为扇内三角形的公用点，绘制出四个小的等腰三角形拼接
      * webgl是逆时针方向渲染的
      */
      var points = [
        165, 165, 255, 255, 0, 1, //V0
        30, 30, 255, 0, 0, 1,    //V1
        30, 300, 255, 0, 0, 1,   //V2
        300, 300, 255, 0, 0, 1,  //V3
        300, 30, 0, 255, 0, 1,   //V4
        30, 30, 255, 0, 0, 1,    //V1
      ];

      var points2 = [
        300, 30, 0, 255, 0, 1,   //V4
        30, 30, 255, 0, 0, 1,    //V1
        30, 300, 255, 0, 0, 1,   //V2
        300, 300, 255, 0, 0, 1,  //V3
      ];
      // 创建一个定位缓冲区
      var buffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
      gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 24, 0);
      gl.vertexAttribPointer(aColor, 4, gl.FLOAT, false, 24, 8);
  
      function draw(count) {
        var pointList = count === 'four' ? points : points2;
        // 设置清空画布的颜色为黑色
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        // 用上一步设置的颜色清空画布
        gl.clear(gl.COLOR_BUFFER_BIT);
        // 往缓冲区内写入数据 Float32Array是因为glsl是强类型的，所以需要将数组同样转成抢类型
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(pointList), gl.STATIC_DRAW);
        // gl.TRIANGLE_STARIP表示的是三角带图元
        /**
        * @param mode 表示图元类型
        * @param first 表示从第几个点开始绘制
        * @param 表示需要绘制的点的数量
        */
        gl.drawArrays(gl.TRIANGLE_FAN, 0, pointList.length / 6);
      }
      draw('four');

      var inputs = document.querySelectorAll('input');
      for (var i = 0; i < inputs.length; i++) {
        inputs[i].addEventListener('input', function(event) {
          draw(event.target.value);
        }, false);
      }
    })();
  </script>
</body>
</html>